﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Galaktika.BI.Runtime.Services;
using Galaktika.BI.Silverlight.Intermediate;

namespace Galaktika.BI.Silverlight.Controls
{
    public partial class ImageKPI : ContentControl, IBindableObject, IEditableObject
    {
        //private ContentControl  panelCaptionKPI = new ContentControl();
        //private ContentControl panelCaptionValue = new ContentControl();
        //private ContentControl panelStateImage = new ContentControl();
        private ImageControl pictStateImage = new ImageControl();
        private LabelControl labelCaptionKPI = new LabelControl();
        private LabelControl labelCaptionValue = new LabelControl();

        private bool m_UpdatingKPI = false;
        private object m_ValueOld;
        private object m_MaxValueOld;
        private object m_MinValueOld;
        private object m_HiValueOld;
        private object m_LoValueOld;
        private double m_dValue;
        private double m_dMaxValue;
        private double m_dMinValue;
        private double m_dHiValue;
        private double m_dLoValue;
        private double m_dScoreValue;
        private double m_dActualMaxValue;
        private double m_dActualMinValue;

        private Storyboard resDoubleClickTimer;

        /// <summary> 
        /// Required designer variable.
        /// </summary>
        public ImageKPI()
        {

            this.VerticalContentAlignment = VerticalAlignment.Stretch;
            this.HorizontalContentAlignment = HorizontalAlignment.Stretch;

            resDoubleClickTimer = new Storyboard();
            resDoubleClickTimer.Duration = new Duration(TimeSpan.FromMilliseconds(250.0));
            resDoubleClickTimer.Completed += new EventHandler(resDoubleClickTimer_Completed);
            base.MouseLeftButtonDown += new MouseButtonEventHandler(ImageKPI_MouseLeftButtonDown);

            base.MouseLeftButtonUp += new MouseButtonEventHandler(ImageKPI_MouseLeftButtonUp);
        }

        void ImageKPI_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            m_ClickCount++;
            m_LastArgs = e;
            resDoubleClickTimer.Begin();
        }

        private byte m_ClickCount = 0;
        MouseButtonEventArgs m_LastArgs;
        void resDoubleClickTimer_Completed(object sender, EventArgs e)
        {
            if (m_ClickCount > 1)
            {
                this.OnMouseDoubleClick(m_LastArgs);
            }
            m_ClickCount = 0;
        }

        public event MouseButtonEventHandler MouseDoubleClick;
        protected void OnMouseDoubleClick(MouseButtonEventArgs e)
        {
            if (this.MouseDoubleClick != null)
            {
                this.MouseDoubleClick(this, e);
            }
        }

        void ImageKPI_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            this.OnMouseClick(e);
        }

        public event MouseButtonEventHandler MouseClick;
        protected void OnMouseClick(MouseButtonEventArgs e)
        {
            if (this.MouseClick != null)
            {
                this.MouseClick(this, e);
            }
        }

        #region CaptionKPI Appearance
        public Color ACaptionBackColor 
        {
            get
            {
                return labelCaptionKPI.ABackColor;
            }
            set
            {
                labelCaptionKPI.ABackColor = value;
            }
        }
        
        public Color ACaptionForeColor 
        {
            get
            {
                return labelCaptionKPI.AForeColor;
            }
            set
            {
                labelCaptionKPI.AForeColor = value;
            }
        }
       
        public Font ACaptionFont
        {
            get
            {
                return labelCaptionKPI.AFont;
            }
            set
            {
                labelCaptionKPI.AFont = value;
            }
        }

       
        public BorderStyles ACaptionBorderStyle
        {
            get
            {
                return labelCaptionKPI.ABorderStyle;
            }
            set
            {
                labelCaptionKPI.ABorderStyle = value;
            }
        }


        public System.Windows.Style ACaptionStyle
        {
            get
            {
                return labelCaptionKPI.Style;
            }
            set
            {
                labelCaptionKPI.Style = value;
            }
        }
        

        //public string ACaptionSkinName
        //{
        //    get
        //    {
        //        return labelCaptionKPI.LookAndFeel.SkinName;
        //    }
        //    set
        //    {
        //        labelCaptionKPI.LookAndFeel.SetSkinStyle(value);
        //        panelCaptionKPI.LookAndFeel.SetSkinStyle(value);
        //    }
        //}
        
        #endregion CaptionKPI Appearance

        #region ValueKPI Appearance
        public Color AValueBackColor
        {
            get
            {
                return labelCaptionValue.ABackColor;
            }
            set
            {
                labelCaptionValue.ABackColor = value;
            }
        }


        public Color AValueForeColor
        {
            get
            {
                return labelCaptionValue.AForeColor;
            }
            set
            {
                labelCaptionValue.AForeColor = value;
            }
        }


        public Font AValueFont
        {
            get
            {
                return labelCaptionValue.AFont;
            }
            set
            {
                labelCaptionValue.AFont = value;
            }
        }


        public BorderStyles AValueBorderStyle
        {
            get
            {
                return labelCaptionValue.ABorderStyle;
            }
            set
            {
                labelCaptionValue.ABorderStyle = value;
            }
        }


        //public string AValueSkinName
        //{
        //    get
        //    {
        //        return labelCaptionValue.LookAndFeel.SkinName;
        //    }
        //    set
        //    {
        //        labelCaptionValue.LookAndFeel.SetSkinStyle(value);
        //        panelCaptionValue.LookAndFeel.SetSkinStyle(value);
        //    }
        //}


        public Style AValueStyle
        {
            get
            {
                return labelCaptionValue.Style;
            }
            set
            {
                labelCaptionValue.Style = value;
            }
        }

        #endregion ValueKPI Appearance

        #region Common Appearance
        public PictureSizeMode APictureSizeMode
        {
            get
            {
                return pictStateImage.ASizeMode;
            }
            set
            {
                pictStateImage.ASizeMode = value;
            }
        }

        private bool showToolTips = true;
        public bool AShowToolTips
        {
            get
            {
                return showToolTips;
            }
            set
            {
                showToolTips = value;
                if (value == true)
                    this.pictStateImage.AToolTipText = toolTipText;
                else
                    this.pictStateImage.AToolTipText = string.Empty;
            }
        }


        private string toolTipText = "";
        public string AToolTipText
        {
            get
            {
                return toolTipText;
            }
            set
            {
                toolTipText = value;
                if (showToolTips)
                    this.pictStateImage.AToolTipText = value;
            }
        }


        public Cursor ACursor
        {
            get
            {
                return this.pictStateImage.Cursor;
            }
            set
            {
                this.pictStateImage.Cursor = value;
            }
        }
        #endregion Common Appearance

        #region Data Properties
        private byte[] m_BadImage = null;
        public byte[] ABadImage
        {
            get
            {
                return m_BadImage;
            }
            set
            {
                m_BadImage = value;
            }
        }

        private byte[] m_MidImage = null;
        public byte[] AMidImage
        {
            get
            {
                return m_MidImage;
            }
            set
            {
                m_MidImage = value;
            }
        }

        private byte[] m_GoodImage = null;
        public byte[] AGoodImage
        {
            get
            {
                return m_GoodImage;
            }
            set
            {
                m_GoodImage = value;
            }
        }

        public byte[] ACurrentImage
        {
            get
            {
                return pictStateImage.AImage;
            }
            set
            {
                pictStateImage.AImage = value;
            }
        }

        private object m_MaxValue;
        private object m_ActualMaxValue = 0;
        public object AMaxValue
        {
            get
            {
                return m_MaxValue;
            }
            set
            {
                m_MaxValue = value;
                m_ActualMaxValue = value;
            }
        }

        private object m_MinValue;
        private object m_ActualMinValue = 0;
        public object AMinValue
        {
            get
            {
                return m_MinValue;
            }
            set
            {
                m_MinValue = value;
                m_ActualMinValue = value;
            }
        }

        private object m_HiValue;
        public object AHiValue
        {
            get
            {
                return m_HiValue;
            }
            set
            {
                m_HiValue = value;
            }
        }

        private object m_LoValue;
        public object ALoValue
        {
            get
            {
                return m_LoValue;
            }
            set
            {
                m_LoValue = value;
            }
        }

        private object m_Value;
        public object AValue
        {
            get
            {
                return m_Value;
            }
            set
            {
                m_Value = value;
            }
        }

        private Intermediate.ValueType m_ValueType = Intermediate.ValueType.ActualValue;
        public string AValueType
        {
            get { return m_ValueType.ToString(); }
            set
            {
                Intermediate.ValueType _ValueTypeNew = (Intermediate.ValueType)Enum.Parse(typeof(Intermediate.ValueType), value, true);
                if (m_ValueType != _ValueTypeNew)
                {
                    m_ValueType = _ValueTypeNew;

                    // если задан просмотр относительных значений, тогда запоминаю 
                    // абсолютные значения для корректного преобразования в относительные значения
                    if (m_ValueType == Intermediate.ValueType.ScoreValue)
                    {
                        m_ActualMaxValue = m_MaxValue;
                        m_ActualMinValue = m_MinValue;
                    }
                }
            }
        }

        private bool m_ShowValue = true;
        public bool AShowValue
        {
            
             get
             {
                 return m_ShowValue;
             }
             set
             {
                 m_ShowValue = value;
                 //if (value == false)
                 //{
                 //    panelCaptionValue.Visible = false;
                 //}
                 //else
                 //{
                 //    panelCaptionValue.Visible = true;
                 //}
             }
        }

        private string m_FormatString = "";
        public string AFormatString
        {
            get
            {
                return m_FormatString;
            }
            set
            {
                m_FormatString = value;
            }
        }

        private string m_KPIValue = string.Empty;
        public string AKPIValue
        {
            get
            {
                return m_KPIValue;
            }
            set
            {
                m_KPIValue = value;
            }
        }

        public string AKPICaption
        {
            get
            {
                return labelCaptionKPI.AText;
            }
            set
            {
                labelCaptionKPI.AText = value;
            }
        }

       public string AValueCaption
        {
            get
            {
                return labelCaptionValue.AText;
            }
            set
            {
                labelCaptionValue.AText = value;
            }
        }
        #endregion

        #region Private Methods

        // перерасчет относительного значения
        private void RecalcScoreValue()
        {
            double _Distance = m_dActualMaxValue - m_dActualMinValue;

            // определяю величину значения в относительных единицах
            if (m_ValueType == Intermediate.ValueType.ScoreValue)
            {
                m_dScoreValue = ((m_dValue - m_dMinValue) / _Distance) * 100;
            }
        }

        // преобразование типа object к типу double
        // true - успешное преобразование; false - неуспешное 
        private bool TryConvertObjectToDouble()
        {
            try
            {
                m_dValue = Convert.ToDouble(m_Value);
                m_dMaxValue = Convert.ToDouble(m_MaxValue);
                m_dMinValue = Convert.ToDouble(m_MinValue);
                m_dHiValue = Convert.ToDouble(m_HiValue);
                m_dLoValue = Convert.ToDouble(m_LoValue);
                m_dActualMaxValue = Convert.ToDouble(m_ActualMaxValue);
                m_dActualMinValue = Convert.ToDouble(m_ActualMinValue);

                return true;
            }
            catch (InvalidCastException)
            {
                m_dValue = 0;
                m_dMaxValue = 0;
                m_dMinValue = 0;
                m_dHiValue = 0;
                m_dLoValue = 0;
                m_dActualMaxValue = 0;
                m_dActualMinValue = 0;
                return false;
            }
        }

        /// <summary>
        /// Получает картинку из массива байт.
        /// </summary>
        /// <param name="imageByte"></param>
        /// <returns></returns>
        private Image GetImage(byte[] imageByte)
        {
            MemoryStream stream = new MemoryStream();
            stream.Write(imageByte, 0, imageByte.Length);
            BitmapImage bi = new BitmapImage();
            bi.SetSource(stream);
            Image image = new Image();
            image.Source = bi;
            return image;
        }

        // в зависимости от значения настраивает отображаемую картинку и заголовок 
        private void UpdateKPIState()
        {
            AKPICaption = AKPIValue;

            // если хоть одно значение равно null, тогда выдаю сообщение "нет данных"
            if (AMaxValue == null || AMinValue == null ||
                AHiValue == null || ALoValue == null ||
                AValue == null)
            {
                AKPICaption = Localization.Ctrl_KPINoData;
                AValueCaption = "";
                ACurrentImage = ABadImage;
                return;
            }

            // если преобразование из типа object в тип double неуспешное
            // тогда вывожу соответствующее сообщение
            if (TryConvertObjectToDouble())
            {
                AValueCaption = "";
                double _Value = 0;
                if (m_ValueType == Intermediate.ValueType.ActualValue)
                {
                    _Value = m_dValue;
                    AValueCaption = _Value.ToString();
                }
                else if (m_ValueType == Intermediate.ValueType.ScoreValue)
                {
                    // перерассчитываю относительное значение
                    RecalcScoreValue();

                    _Value = m_dScoreValue;
                    AValueCaption = String.Format("{0:P}", _Value / 100);
                }

                // если диапазон задан правильно
                if ((m_dMinValue < m_dLoValue) && (m_dLoValue <= m_dHiValue) && (m_dHiValue < m_dMaxValue) &&
                     (m_dValue >= m_dMinValue) && (m_dValue <= m_dMaxValue))
                {
                    // в зависимости от значения вывожу нужную картинку
                    if (m_dValue < m_dLoValue)
                    {
                        ACurrentImage = m_BadImage;
                    }
                    else if ((m_dValue >= m_dLoValue) && (m_dValue < m_dHiValue))
                    {
                        ACurrentImage = AMidImage;
                    }
                    else if (m_dValue >= m_dHiValue)
                    {
                        ACurrentImage = AGoodImage;
                    }
                }
                else  // диапазон задан неверно
                {
                    AKPICaption = Localization.Ctrl_KPIDataNotValid;
                    ACurrentImage = ABadImage;
                }
            }
            else
            {
                AKPICaption = Localization.Ctrl_KPINoData;
                ACurrentImage = ABadImage;
                return;
            }
        }

        #endregion Private Methods

        #region IEditableObject members
        void IEditableObject.BeginEdit()
        {
            if (!m_UpdatingKPI)
            {
                m_ValueOld = AValue;
                m_MaxValueOld = AMaxValue;
                m_MinValueOld = AMinValue;
                m_HiValueOld = AHiValue;
                m_LoValueOld = ALoValue;

                m_UpdatingKPI = true;
            }
        }

        void IEditableObject.CancelEdit()
        {
            if (m_UpdatingKPI)
            {
                AValue = m_ValueOld;
                AMaxValue = m_MaxValueOld;
                AMinValue = m_MinValueOld;
                AHiValue = m_HiValueOld;
                ALoValue = m_LoValueOld;

                m_UpdatingKPI = false;
            }
        }

        void IEditableObject.EndEdit()
        {
            if (m_UpdatingKPI)
            {
                m_UpdatingKPI = false;
                UpdateKPIState();
            }

            labelCaptionKPI.EndEdit();
            labelCaptionKPI.HorizontalAlignment = HorizontalAlignment.Stretch;
            labelCaptionKPI.HorizontalContentAlignment = HorizontalAlignment.Center;
            labelCaptionValue.EndEdit();
            labelCaptionValue.HorizontalAlignment = HorizontalAlignment.Stretch;
            labelCaptionValue.HorizontalContentAlignment = HorizontalAlignment.Center;

            pictStateImage.AImage = ACurrentImage;
            pictStateImage.EndEdit();
            if (base.Content is Grid)
                (base.Content as Grid).Children.Clear();
            Grid stackPanel = new Grid();
            //stackPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
            //stackPanel.VerticalAlignment = VerticalAlignment.Stretch;
            if (!string.IsNullOrEmpty(this.AKPICaption))
            {
                stackPanel.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
                Grid.SetRow(labelCaptionKPI, 0);
                stackPanel.Children.Add(labelCaptionKPI);
            }
            if (AShowValue)
            {
                stackPanel.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
                Grid.SetRow(labelCaptionValue, 1);
                stackPanel.Children.Add(labelCaptionValue);
            }
            Image image = GetImage(ACurrentImage);
            //image.HorizontalAlignment = HorizontalAlignment.Stretch;
            //image.VerticalAlignment = VerticalAlignment.Stretch;
            image.Stretch = this.APictureSizeMode.ToStretch();

            stackPanel.RowDefinitions.Add(new RowDefinition());
            Grid.SetRow(pictStateImage, stackPanel.RowDefinitions.Count - 1);

            stackPanel.Children.Add(pictStateImage);

            base.Content = stackPanel;
        }
        #endregion

        #region IBindableObject Members

        private IBindingContext m_Context;
        public IBindingContext Context
        {
            get
            {
                return m_Context;
            }
            set
            {
                m_Context = value;
            }
        }

        private Dictionary<string, IBindingManager> m_Bindings;
        public IDictionary<string, IBindingManager> Bindings
        {
            get
            {
                if (m_Bindings == null)
                {
                    m_Bindings = new Dictionary<string, IBindingManager>();
                }

                return m_Bindings;
            }
        }

        #endregion

        private void pictStateImage_Click(object sender, EventArgs e)
        {
            //base.OnMouseClick(new MouseEventArgs(MouseButtons.Left, 0, 0, 0, 0));
        }

        //ToDo: доделать события...
        private void pictStateImage_MouseClick(object sender, MouseEventArgs e)
        {
            //base.OnMouseClick(e);
        }
    }
}

